/*-------------------------------------------------------------------------
 *
 * copyfrom_internal.h
 *	  COPY FROM 命令的内部定义。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/commands/copyfrom_internal.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef COPYFROM_INTERNAL_H
#define COPYFROM_INTERNAL_H

#include "commands/copy.h"
#include "commands/trigger.h"

/*
 * 表示我们在底层需要关注的不同源案例
 */
typedef enum CopySource
{
	COPY_FILE,					/* 从文件（或管道程序） */
	COPY_FRONTEND,				/* 从前端 */
	COPY_CALLBACK				/* 从回调函数 */
} CopySource;

/*
 * 表示输入的行结束符类型
 */
typedef enum EolType
{
	EOL_UNKNOWN,
	EOL_NL,
	EOL_CR,
	EOL_CRNL
} EolType;

/*
 * 表示在COPY FROM过程中使用的堆插入方法。
 */
typedef enum CopyInsertMethod
{
	CIM_SINGLE,					/* 使用table_tuple_insert或fdw例程 */
	CIM_MULTI,					/* 始终使用table_multi_insert */
	CIM_MULTI_CONDITIONAL		/* 仅在有效时使用table_multi_insert */
} CopyInsertMethod;

/*
 * 此结构包含在COPY FROM操作中使用的所有状态变量。
 */
typedef struct CopyFromStateData
{
	/* 低级状态数据 */
	CopySource	copy_src;		/* 复制源的类型 */
	FILE	   *copy_file;		/* 如果copy_src == COPY_FILE则使用 */
	StringInfo	fe_msgbuf;		/* 如果copy_src == COPY_NEW_FE则使用 */

	EolType		eol_type;		/* 输入的EOL类型 */
	int			file_encoding;	/* 文件或远程端的字符编码 */
	bool		need_transcoding;	/* 文件编码与服务器不同？ */
	Oid			conversion_proc;	/* 编码转换函数 */

	/* COPY 命令的参数 */
	Relation	rel;			/* 待复制关系 */
	List	   *attnumlist;		/* 要复制的 attnums 的整数列表 */
	char	   *filename;		/* 文件名，或者为NULL表示STDIN */
	bool		is_program;		/* 'filename' 是一个程序以 popen 吗？ */
	copy_data_source_cb data_source_cb; /* 读取数据的函数 */

	CopyFormatOptions opts;
	bool	   *convert_select_flags;	/* 每列的 CSV/TEXT CS 标志 */
	Node	   *whereClause;	/* WHERE 条件（或 NULL） */

	/* 这些只是用于错误消息，请参阅 CopyFromErrorCallback */
	const char *cur_relname;	/* 错误消息的表名 */
	uint64		cur_lineno;		/* 错误消息的行号 */
	const char *cur_attname;	/* 错误消息的当前属性 */
	const char *cur_attval;		/* 错误消息的当前属性值 */

	/*
	 * 工作状态
	 */
	MemoryContext copycontext;	/* 每个复制执行上下文 */

	AttrNumber	num_defaults;
	FmgrInfo   *in_functions;	/* 每个属性的输入函数数组 */
	Oid		   *typioparams;	/* in_functions 的元素类型数组 */
	int		   *defmap;			/* 默认属性编号数组 */
	ExprState **defexprs;		/* 默认属性表达式数组 */
	bool		volatile_defexprs;	/* defexprs 中是否有任何是易失性的？ */
	List	   *range_table;
	ExprState  *qualexpr;

	TransitionCaptureState *transition_capture;

	/*
	 * 这些变量用于减少 COPY FROM 的开销。
	 *
	 * attribute_buf 保存当前行每个字段的分隔、去转义文本。 
	 * CopyReadAttributes 函数返回指向此缓冲区的指针数组。我们通过在每个周期重用
	 * 缓冲区来避免 palloc/pfree 的开销。
	 *
	 * 在二进制 COPY FROM 中，attribute_buf 保存当前字段的二进制数据，
	 * 但用法基本相似。
	 */
	StringInfoData attribute_buf;

	/* COPY FROM 找到的字段原始数据指针 */

	int			max_fields;
	char	  **raw_fields;

	/*
	 * 类似地，line_buf 保存正在处理的整个输入行。输入周期首先将整行读入 line_buf，
	 * 然后提取单个属性字段到 attribute_buf。line_buf 保持未修改，以便在出现错误消息时
	 * 适当显示。（在二进制模式下，不使用 line_buf。）
	 */
	StringInfoData line_buf;
	bool		line_buf_valid; /* 是否包含正在处理的行？ */

	/*
	 * input_buf 保存输入数据，已经转换为数据库编码。
	 *
	 * 在文本模式下，CopyReadLine 足够解析此数据以定位行边界，
	 * 然后将数据传输到 line_buf。我们保证在任何时候 input_buf[input_buf_len] 处
	 * 存在 \0。（在二进制模式下，不使用 input_buf。）
	 *
	 * 如果不需要编码转换，input_buf 不是单独的缓冲区，而是指向 raw_buf。
	 * 在这种情况下，input_buf_len 跟踪在数据库编码中已验证为有效的字节数，
	 * 而 raw_buf_len 是缓冲区中存储的字节总数。
	 */
#define INPUT_BUF_SIZE 65536	/* 我们分配 INPUT_BUF_SIZE+1 字节 */
	char	   *input_buf;
	int			input_buf_index;	/* 下一个要处理的字节 */
	int			input_buf_len;	/* 存储的字节总数 */
	bool		input_reached_eof;	/* 如果到达 EOF 则为真 */
	bool		input_reached_error;	/* 如果发生转换错误则为真 */
	/* 输入缓冲区中可用的未消耗字节的简写 */
#define INPUT_BUF_BYTES(cstate) ((cstate)->input_buf_len - (cstate)->input_buf_index)

	/*
	 * raw_buf 保存从数据源（文件或客户端连接）读取的原始输入数据，
	 * 尚未转换为数据库编码。与 'input_buf' 一样，我们保证
	 * 在 raw_buf[raw_buf_len] 处存在 \0。
	 */
#define RAW_BUF_SIZE 65536		/* 我们分配 RAW_BUF_SIZE+1 字节 */
	char	   *raw_buf;
	int			raw_buf_index;	/* 下一个要处理的字节 */
	int			raw_buf_len;	/* 存储的字节总数 */
	bool		raw_reached_eof;	/* 如果到达 EOF 则为真 */

	/* raw_buf 中可用的未消耗字节的简写 */
#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)

	uint64		bytes_processed;	/* 到目前为止处理的字节数 */
} CopyFromStateData;

extern void ReceiveCopyBegin(CopyFromState cstate);
extern void ReceiveCopyBinaryHeader(CopyFromState cstate);

#endif							/* COPYFROM_INTERNAL_H */
